using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.ObjectBuilder;
using Microsoft.Practices.CompositeWeb.Interfaces;
using Microsoft.Practices.CompositeWeb.Utility;
using Microsoft.Practices.CompositeWeb.Services;
using System.Collections;
using System.Web.SessionState;
using Microsoft.Practices.CompositeWeb;

namespace WCSFContrib.Extensions.CompositeWeb
{
    /// <summary>
    /// Indicates that property or parameter should get a reference to a shared instance
    /// and should be dependency injected when the class is put into a <see cref="CompositionContainer"/>.
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)]
    public sealed class CreateSharedAttribute : ParameterAttribute
    {
        private string _key = null;
        /// <summary>
        /// Gets or sets the key that will identify the shared instance
        /// </summary>
        public string Key
        {
            get { return _key; }
            set { _key = value; }
        }

        /// <summary>
        /// See <see cref="ParameterAttribute.CreateParameter"/> for more information.
        /// </summary>
        public override IParameter CreateParameter(Type memberType)
        {
            return new CreateSharedParameter(memberType, memberType.ToString() + ";" + _key ?? string.Empty );
        }

        class CreateSharedParameter : IParameter
        {
            Type _instanceType;
            string _key;

            public CreateSharedParameter(Type instanceType, string key)
            {
                _instanceType = instanceType;
                _key = key;
            }

            #region IParameter Members

            public Type GetParameterType(IBuilderContext context)
            {
                return _instanceType;
            }

            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods", Justification = "Validation done by Guard class.")]
            public object GetValue(IBuilderContext context)
            {
                Guard.ArgumentNotNull(context, "context");
                CompositionContainer container = (CompositionContainer) context.Locator.Get(new DependencyResolutionLocatorKey(typeof(CompositionContainer), null));
                object instance = null;
                IHttpContextLocatorService contextLocator = container.Locator.Get<IHttpContextLocatorService>(new DependencyResolutionLocatorKey(typeof(IHttpContextLocatorService), null));
                IHttpContext httpContext = contextLocator.GetCurrentContext();
                if (!httpContext.Items.Contains(_key))
                {
                    Type itemType = container.GetMappedType(_instanceType);
                    instance = container.BuildNewItem(itemType);
                    httpContext.Items.Add(_key, instance);
                }
                else
                {
                    instance = httpContext.Items[_key];
                }
                return instance;
            }

            #endregion
        }
    }
}
